/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.sentry.protocol;

import io.sentry.IUnknownPropertiesConsumer;
import io.sentry.util.CollectionUtils;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

/**
 * App
 *
 * @since 2021-06-02
 **/
public final class App implements IUnknownPropertiesConsumer, Cloneable {
    /**
     * type
     */
    public static final String TYPE = "app";

    /**
     * Version-independent application identifier, often a dotted bundle ID.
     */
    private @Nullable String appIdentifier;
    /**
     * Start time of the app.
     *
     * <p>Formatted UTC timestamp when the user started the application.
     */
    private @Nullable Date appStartTime;
    /**
     * Application-specific device identifier.
     */
    private @Nullable String deviceAppHash;
    /**
     * String identifying the kind of build. For example, `testflight`.
     */
    private @Nullable String buildType;
    /**
     * Application name as it appears on the platform.
     */
    private @Nullable String appName;
    /**
     * Application version as it appears on the platform.
     */
    private @Nullable String appVersion;
    /**
     * Internal build ID as it appears on the platform.
     */
    private @Nullable String appBuild;

    @SuppressWarnings("unused")
    private @Nullable Map<String, @NotNull Object> unknown;

    public @Nullable String getAppIdentifier() {
        return appIdentifier;
    }

    public void setAppIdentifier(final @Nullable String appIdentifier) {
        this.appIdentifier = appIdentifier;
    }

    /**
     * get app start Date
     *
     * @return app start Date
     */
    @SuppressWarnings({"JdkObsolete", "JavaUtilDate"})
    public @Nullable Date getAppStartTime() {
        final Date appStartTimeRef = appStartTime;
        return appStartTimeRef != null ? (Date) appStartTimeRef.clone() : null;
    }

    public void setAppStartTime(final @Nullable Date appStartTime) {
        if(appStartTime != null){
            this.appStartTime = (Date) appStartTime.clone();
        }
    }

    public @Nullable String getDeviceAppHash() {
        return deviceAppHash;
    }

    public void setDeviceAppHash(final @Nullable String deviceAppHash) {
        this.deviceAppHash = deviceAppHash;
    }

    public @Nullable String getBuildType() {
        return buildType;
    }

    public void setBuildType(final @Nullable String buildType) {
        this.buildType = buildType;
    }

    public @Nullable String getAppName() {
        return appName;
    }

    public void setAppName(final @Nullable String appName) {
        this.appName = appName;
    }

    public @Nullable String getAppVersion() {
        return appVersion;
    }

    public void setAppVersion(final @Nullable String appVersion) {
        this.appVersion = appVersion;
    }

    public @Nullable String getAppBuild() {
        return appBuild;
    }

    public void setAppBuild(final @Nullable String appBuild) {
        this.appBuild = appBuild;
    }

    @TestOnly
    @Nullable
    Map<String, Object> getUnknown() {
        return unknown;
    }

    @ApiStatus.Internal
    @Override
    public void acceptUnknownProperties(@NotNull Map<String, Object> unknowns) {
        this.unknown = new ConcurrentHashMap<>(unknowns);
    }

    /**
     * Clones an App aka deep copy
     *
     * @return the cloned App
     * @throws CloneNotSupportedException if object is not cloneable
     */
    @Override
    public @NotNull App clone() throws CloneNotSupportedException {
        final App clone = (App) super.clone();

        clone.unknown = CollectionUtils.newConcurrentHashMap(unknown);

        return clone;
    }
}
